//package com.xjd.edu.toolkit.limit;
//
//import cn.hutool.core.util.StrUtil;
//import com.alibaba.csp.sentinel.Entry;
//import com.alibaba.csp.sentinel.SphU;
//import com.alibaba.csp.sentinel.slots.block.BlockException;
//import com.xjd.edu.toolkit.exception.BlockingException;
//import io.netty.util.concurrent.DefaultThreadFactory;
//import lombok.extern.slf4j.Slf4j;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Qualifier;
//import org.springframework.core.env.StandardEnvironment;
//import org.springframework.util.CollectionUtils;
//import org.springframework.util.StringUtils;
//
//import java.util.HashSet;
//import java.util.Set;
//import java.util.concurrent.Executors;
//import java.util.concurrent.TimeUnit;
//import java.util.function.Supplier;
//
///**
// * Redis限流控制器，基于 Sentinel 实现，一个工程最多只能有一个实例
// *
// * @author wangyu
// * @since 2023/3/28
// */
//@Slf4j
//public class RedisLimitCtrl {
//
//    /**
//     * 用于解决重新加载限流规则时，旧规则还未失效的问题
//     */
//    private String preRuleValue;
//
//    /**
//     * 限流规则键集合（允许使用正则表达式）
//     */
//    private Set<String> patterns;
//
//    @Autowired(required = false)
//    @Qualifier("redisLimitCtrlSupplier")
//    private Supplier<String> redisLimitCtrlSupplier;
//
//    public RedisLimitCtrl(StandardEnvironment environment) {
//
//        // 限流规则刷新频率，默认 5s，最小 5s
//        final int interval = Math.max(environment.getProperty("biz.limit.redis.refresh_interval_seconds", Integer.class, 5), 5);
//
//        // 每5秒重新加载限流规则
//        Executors.newSingleThreadScheduledExecutor(new DefaultThreadFactory("redis-limit-refresh")).scheduleAtFixedRate(() -> {
//            try {
//                reloadRules(environment);
//            } catch (Exception e) {
//                log.error("Reload rules error", e);
//            }
//        }, 0, interval, TimeUnit.SECONDS);
//    }
//
//    /**
//     * Redis 键限流
//     *
//     * @param key 非空
//     */
//    public void limit(String key) {
//        if (key == null) {
//            return;
//        }
//
//        if (CollectionUtils.isEmpty(patterns)) {
//            return;
//        }
//
//        // 判断 key 是否符合限流规则，将其转换为对应的限流 pattern 这里会使用正则来匹配某一规则，避免出现键过多的情况
//        for (String pattern : patterns) {
//            if (!key.matches(pattern)) {
//                continue;
//            }
//            try (final Entry ignored = SphU.entry(pattern)) {
//                break;
//            } catch (BlockException e) {
//                log.warn("Redis键触发限流 key: {}, pattern: {}", key, pattern, e);
//                throw new BlockingException();
//            }
//        }
//    }
//
//    /**
//     * 重新加载限流规则
//     *
//     * @param environment 非空
//     */
//    private void reloadRules(StandardEnvironment environment) {
//
//        // 规则开关，如果关闭将清空限流模板
//        final String enabled = environment.getProperty("biz.limit.redis.enabled", "true");
//        if (!StrUtil.equalsIgnoreCase(enabled, "true")) {
//            this.patterns = null;
//            return;
//        }
//
//        if (redisLimitCtrlSupplier == null) {
//            return;
//        }
//
//        final String value = redisLimitCtrlSupplier.get();
//
//        if (log.isDebugEnabled()) {
//            log.debug("Reload redis limit rules, value: {}", value);
//        }
//
//        if (preRuleValue != null && StrUtil.equals(preRuleValue, value)) {
//            return;
//        } else {
//            preRuleValue = value;
//        }
//
//        // 清空限流模板
//        if (!StringUtils.hasText(value)) {
//            patterns = null;
//            return;
//        }
//
//        // 解析限流模板
//        final Set<String> patterns = new HashSet<>();
//        for (String pattern : value.trim().split("\\s*,\\s*")) {
//            if (StringUtils.hasText(pattern)) {
//                patterns.add(pattern);
//            }
//        }
//
//        this.patterns = patterns;
//        log.info("Reload redis limit rules, patterns: {}", patterns);
//    }
//
//}
